package bank;

import bank.connect.ConnectDialog;
import java.util.Enumeration;
import java.util.Hashtable;

import mware_access.MiddlewareService;
import mware_access.NameService;

import bank_access.KontoException;
import bank_access.ManagerImplBase;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

/**
 * Klasse fuer den Mananger der Bank.
 *
 */
public class Bank extends ManagerImplBase {
    // middleware stuff

    private static String Bankname = "Bank04";
    private NameService nameservice;
    private MiddlewareService mware;
    private Hashtable<String, Account> AccountTable; // interne Liste der Konten
    private String AccountPrefix; // fuer bankuebergreifend eindeutige Konto-IDs
    private String BLZ; // eindeutige BLZ
    private int AccountCounter;  // Kontnummernzaehler
    private Object NumberFormatted[] = new Object[1]; // zum Formatieren
    private final ConnectDialog connectDialog = new bank.connect.ConnectDialog(new javax.swing.JFrame(), true);
    private static Logger logger;

    /**
     * Konstruktor.
     *
     * @param accountPrefix Prefix fuer (bankuebergreifend) eindeutige Konto-IDs
     */
    public Bank(String accountPrefix) {
        logger = getLogger();
        connectDialog.setVisible(true);
        mware = MiddlewareService.init(connectDialog.getHost(), connectDialog.getPort());
        nameservice = mware.getNameService();

        AccountTable = new Hashtable<String, Account>();

        // Kontnummernzaehler initialisieren
        AccountCounter = 999;

        // Prefix fuer Konto-IDs dieser Bank
        AccountPrefix = accountPrefix;
        nameservice.rebind(this, Bankname);

        // transferhandler erzeugen und rebinden
        TransferHandler xferhandler = new TransferHandler(nameservice);
        BLZ = "60050101";
        nameservice.rebind(xferhandler, BLZ);
    }

    /**
     * Liefert naechste verfuegbare Konto-ID.
     *
     * @return Neue Konto-ID
     */
    private String getNextAvailID() {
        NumberFormatted[0] = new Integer(AccountCounter++);
        return AccountPrefix + String.format("%010d", NumberFormatted);
    }

    /**
     * Legt ein neues Konto an und traegt es in die angezeigte Liste ein.
     *
     * @return Neues Kontoobjekt
     */
    private Account createAccount() {
        // neue ID
        String newID = getNextAvailID();

        // neues Konto
        Account newAccount = new Account(newID, BLZ);
        newAccount.setConnectionData(connectDialog.getHost(), connectDialog.getPort());

        // ...in die Anzeigeliste
        AccountTable.put(newID, newAccount);
        return newAccount;
    }

    @Override
    public String kontoEinrichten() {
        // Neues Kontoobjekt
        Account newAccount = createAccount();
        // ID des neuen Kontos
        String newID = newAccount.getID();
        logger.info("Konto erfolgreich eingerichtet ID " + newID);

        //Im Namensdienst anmelden
        nameservice.rebind(newAccount, newID);
        logger.info("Konto beim Namensdienst angemeldet ID " + newID);

        return newID;
    }

    /**
     * Liefert Liste mit aktuellen Kontostaenden.
     * (Wird von der GUI benutzt.)
     *
     * @return Liste mit Kontostaenden.
     */
    public Hashtable<String, Double> getList() {
        Hashtable<String, Double> balanceList = new Hashtable<String, Double>();

        Enumeration<String> keys = AccountTable.keys();
        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            balanceList.put(key, new Double(AccountTable.get(key).kontoStand()));
        }
        return balanceList;
    }

    /**
     * @param args
     * @throws KontoException
     */
    public static void main(String[] args) throws KontoException {
        String myName = Bankname;  // fuer Titelleiste
        String myPrefix = "SR";   // fuer Konto-IDs

        // Manager
        Bank myBank = new Bank(myPrefix);

        // GUI
        BankWindow myGUI = new BankWindow(myName, myBank);
        myGUI.setVisible(true);
        new Thread(myGUI).start();  // Aktualisierungsthread der GUI
    }

    /**
     * Creates a logger.
     *
     * @return
     */
    public static Logger getLogger() {
        FileHandler fhandler = null;
        if (logger == null) {
            try {
                fhandler = new FileHandler("Bank.log");
                fhandler.setFormatter(new SimpleFormatter());
                logger = Logger.getLogger("Bank");
                logger.addHandler(fhandler);
                logger.setLevel(Level.INFO);
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return logger;
    }
}
